import { registerApiHandlers, registerCallbacks } from './api-impl';
import { app, BrowserWindow, shell, WebContents } from 'electron';
import { parseArgs } from 'node:util';
import path from 'node:path';
import environment from 'Shared/environment';
import { loggingOverwriteConsoleLogFunctions } from 'Shared/logging';
import { getTempConfig, TEMP_CONFIG_CURRENT_VERSION, writeTempConfig } from './temp-config';
import IdCounter from 'Shared/id-counter';
import { ArgvParsed, argvParseSpec } from './argv';

{
  loggingOverwriteConsoleLogFunctions();
}

// This allows TypeScript to pick up the magic constants that's auto-generated by Forge's Webpack
// plugin that tells the Electron app where to look for the Webpack-bundled app code (depending on
// whether you're running in development or production).
declare const MAIN_WINDOW_WEBPACK_ENTRY: string;
declare const MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY: string;

// We disable security warnings because we have to use unsafe-eval for ajv
// schema compilation. This should not cause an issue since we are still (a) not
// exposing node directly and (b) sanitizing all loaded svg with dompurify.
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true';

if (environment.pkgPortable) app.setPath(
  'userData',
  path.resolve(path.dirname(app.getAppPath()), '..', 'user', 'data')
);

export const instances: Map<WebContents, {
  win: BrowserWindow, pwd: string, argv: ArgvParsed, lastFocused: boolean,
  id: number,
}> = new Map();

const instanceIds = new IdCounter();

export function createWindow(argv: ArgvParsed, pwd: string) {
  const tempCfg = getTempConfig();
  const win = new BrowserWindow({
    width: tempCfg.windowWidth,
    height: tempCfg.windowHeight,
    webPreferences: {
      preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY,
    },
  })
  win.setMenu(null);
  if (tempCfg.maximized) win.maximize();


  if (!app.isPackaged) win.webContents.openDevTools();
  if (process.argv.indexOf('--dev-tools') !== -1)
    win.webContents.openDevTools();

  win.loadURL(MAIN_WINDOW_WEBPACK_ENTRY);

  win.webContents.setWindowOpenHandler(details => {
    shell.openExternal(details.url);
    return { action: 'deny' };
  });

  try {
    registerCallbacks(win);
  } catch {
    win.webContents.openDevTools();
  }

  instances.set(win.webContents, {
    win, argv, pwd, lastFocused: true, id: instanceIds.nextId()
  });

  win.on('close', () => {

    // when a window is closed and another one is not immediatly focused, we set
    // lastFocused to the first window to still have some sane value
    if (instances.get(win.webContents).lastFocused) {
      const instancesV = [...instances.values()];
      if (instancesV.length !== 0) instancesV[0].lastFocused = true;
    }

    writeTempConfig({
      version: TEMP_CONFIG_CURRENT_VERSION,
      windowHeight: win.getBounds().height,
      windowWidth: win.getBounds().width,
      maximized: win.isMaximized(),
    })
  });

  win.on('focus', () => {
    for (const instance of instances.values()) instance.lastFocused = false;
    instances.get(win.webContents).lastFocused = true;
  });

  win.show();
}

const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
  app.quit();
} else {
  registerApiHandlers();
  app.whenReady().then(() => createWindow(
    parseArgs({ args: process.argv, ...argvParseSpec}), process.cwd()
  ));
  app.on('window-all-closed', () => {
    app.quit();
  });
}
